import os
import pickle
import platform
import socket
import threading
import inspect
import time

import BaseConfig
from Components.MapReduce import MapReduce
from Components.ServerNodeManage import ServerNodeManage
from Exception import ConfigerError, taskError, DataError


class Oneesama:
    def __init__(self, *, Config: BaseConfig.BaseConfig):
        self.Config = Config
        self.startAccept = False
        self.SocketList = list()

        self.console = self.Config.GetConsoleLog()
        self.port = Config.GetPort()
        self.tmp_task = ...
        self.data_iter = ...
        self.argument = None

    @property
    def sisters_count(self):
        return len(self.Config.sisters)

    def set_datas(self, data, map_it=None):
        """
        设置 datas 给 Oneesama
        :param data: 数据 需要是 多维列表
        :param map_it: 是否将他们分成一块一块的 默认是否
        :return:
        """
        if map_it is None:
            self.data_iter = MapReduce.Map(data, self.sisters_count)
        else:
            self.data_iter = data

    def set_task(self, task, *, arg=tuple()):
        """
        设置 task 给 Oneesama
        :param task:
        :param arg:
        :return:
        """

        if arg != ():
            self.argument = arg
        self.tmp_task = task

    def _validate_data_task(self):
        if self.tmp_task is ...:
            raise taskError("No Task to Configed")
        if self.data_iter is ...:
            raise DataError("No Data to Configed")

        source = inspect.getsource(self.tmp_task)
        return source.encode('utf-8')

    def wait_result(self):
        self.console.using_method(f"【Oneesama】等待Sister处理中")

    def command_line(self):
        self.console.using_method("【Oneesama 启动命令行模式中...】")
        time.sleep(4)
        system = platform.architecture()[1]
        if "Window" in system:
            # os.system('cls')
            ...
        elif "Linux" in system:
            # os.system("clear")
            ...
        while True:
            command = input(">>> ")

    def give_all_sister(self):
        """
        将设置好的 数据人物 交给 子服务器
        :return:
        """
        byte_tasks = self._validate_data_task()
        for index, i in enumerate(self.SocketList):
            socket_tmp: socket.socket = i.get("socket")
            if socket_tmp is not None:
                self.console.using_method(f"【Oneesama】正在通知 {i.get('ip')}:{i.get('port')}")

                # self.console.using_method(f"将{self.data_iter[index]}发送给{i.get('ip')}")
                bd = pickle.dumps(self.data_iter[index])
                time.sleep(.5)
                socket_tmp.send(bd)
                time.sleep(.5)

                socket_tmp.send(byte_tasks)
                time.sleep(.5)
                socket_tmp.send(pickle.dumps(self.argument))
                time.sleep(.5)

    def give_sisters(self, *, group="any", name=None):
        """
        将设置好的 数据 任务 交给子服务器
        :return:
        """

        byte_datas, byte_tasks = self._validate_data_task()

        filter_socket_group = [i for i in ServerNodeManage.choose_by_group(group,
                                                                           self.SocketList)]
        filter_socket = filter_socket_group

        if name is not None:
            filter_socket_name = [i for i in ServerNodeManage.choose_by_name(name,
                                                                             filter_socket_group)]
            filter_socket = filter_socket_name

        for i in filter_socket:
            i.send(byte_datas)

    def creat_server(self, timeout=None):
        self.console.using_method(f"【Oneesama】创建服务器 端口{self.port}")
        self.startAccept = True  # 开启服务器
        self.MasterSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.MasterSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # 取消他的WIATTIME
        self.MasterSocket.bind(("", self.port))
        self.MasterSocket.listen(255)
        if timeout is None:
            func_accept = threading.Thread(target=ServerNodeManage.o_get_accept,
                                           args=(self, self.MasterSocket, self.console.using_method))
        else:
            func_accept = threading.Thread(target=ServerNodeManage.o_get_accept,
                                           args=(self, self.MasterSocket, self.console.using_method, timeout))

        func_accept.run()

    def send_2_all(self):
        """
        发送集群激活信息给配置好的服务器
        """

        for i in self.Config.sisters:
            ip = i.get("ip")
            name = i.get("name")
            port = i.get("port")
            group = i.get("group")

            name = name if name is not None else ip
            port = port if port is not None else 10032
            group = group if group is not None else "Any"

            if isinstance(ip, str) and isinstance(name, str):
                self.console.using_method(f"【Oneesama_链接中】提示 名称:{name} ip:{ip} port:{port}的Sister 加入集群")
                socket_to_client = ServerNodeManage.connect((ip, port - 1))
                socket_to_client.close()
                # 这个不是我们使用的通信套接字 而是对子服务器链接的尝试与发送自己信息的套接字
                self.SocketList.append(
                    {"name": name, "ip": ip, "group": group, "port": port}
                )

            else:
                raise ConfigerError("配置类的sister编辑错误")

    def __del__(self):
        for i in self.SocketList:
            i.get("socket").close() if isinstance(i.get('socket'), socket.socket) else ...
